package org.dtrd.modules.questionnaire.service.impl;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.dtrd.config.system.Constant;
import org.dtrd.modules.archive.entity.po.DtrdEntRdArchiveAnamnesis;
import org.dtrd.modules.archive.entity.po.DtrdEntRdArchiveBasic;
import org.dtrd.modules.archive.entity.po.DtrdEntRdArchiveOverview;
import org.dtrd.modules.archive.entity.po.DtrdEntRdArchivePhysical;
import org.dtrd.modules.archive.service.IDtrdEntRdAnamnesisService;
import org.dtrd.modules.archive.service.IDtrdEntRdArchiveBasicService;
import org.dtrd.modules.archive.service.IDtrdEntRdOverviewService;
import org.dtrd.modules.archive.service.IDtrdEntRdPhysicalService;
import org.dtrd.modules.message.util.MsgEventPusher;
import org.dtrd.modules.patient.entity.po.DtrdEntRdPatient;
import org.dtrd.modules.patient.service.IDtrdEntRdPatientService;
import org.dtrd.modules.patient.service.IDtrdRlPatientTagService;
import org.dtrd.modules.questionnaire.entity.bean.PatientBasicInfo;
import org.dtrd.modules.questionnaire.entity.bean.PatientDetailInfo;
import org.dtrd.modules.questionnaire.entity.bean.QuestionnaireRdVersionDetail;
import org.dtrd.modules.questionnaire.entity.bean.QuestionnaireRdVersionListInfo;
import org.dtrd.modules.questionnaire.entity.po.DtrdEntQuestionnaireRdReversion;
import org.dtrd.modules.questionnaire.entity.request.QuestionnaireRdVersionPageRequest;
import org.dtrd.modules.questionnaire.mapper.DtrdEntRdQuestionnaireRdVersionMapper;
import org.dtrd.modules.questionnaire.service.IDtrdEntRdQuestionnaireRdVersionService;
import org.dtrd.modules.util.SchemeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * <p>
 * 调查问卷 服务实现类
 * </p>
 *
 * @author QR
 * @since 2022-02-15
 */
@DS("multi-datasource1")
@Service
public class DtrdEntRdQuestionnaireRdVersionServiceImpl extends ServiceImpl<DtrdEntRdQuestionnaireRdVersionMapper, DtrdEntQuestionnaireRdReversion> implements IDtrdEntRdQuestionnaireRdVersionService {

    @Autowired
    private IDtrdEntRdPatientService patientService;
    @Autowired
    private IDtrdEntRdArchiveBasicService archiveBasicService;
    @Autowired
    private IDtrdEntRdOverviewService overviewService;
    @Autowired
    private IDtrdEntRdPhysicalService physicalService;
    @Autowired
    private IDtrdRlPatientTagService patientTagService;
    @Autowired
    private IDtrdEntRdAnamnesisService anamnesisService;

    /**
     * 未确诊糖尿病
     */
    private final static int NO_DIABETES_DIAGNOSE = 1;

    /**
     * 并发症
     */
    private final static int DIABETES_COMPLICATION = 1;

    /**
     * 糖尿病肾病
     */
    private final static int KETONE_LESION = 3;

    /**
     * 单选
     */
    private final static int SINGLE_CHOICE = 1;

    // 对应着 dtrd_ext_ems_yw_tags 的 可逆转和不可逆转的标签id
    private final static int reversible = 829;
    private final static int irreversible = 830;

    @Autowired
    private MsgEventPusher msgEventPusher;

    @Override
    public IPage<QuestionnaireRdVersionListInfo> pageQuestionnaire(QuestionnaireRdVersionPageRequest request) {
        LambdaQueryWrapper<DtrdEntQuestionnaireRdReversion> queryWrapper = baseQueryWrapper();
        IPage<DtrdEntQuestionnaireRdReversion> page = new Page<>(request.getPageNum(), request.getPageSize());
        page = this.page(page, queryWrapper);
        return page.convert(QuestionnaireRdVersionListInfo::new);
    }

    @Override
    public QuestionnaireRdVersionDetail getQuestionnaireReversion(Integer patientId) {
        DtrdEntRdPatient patient = patientService.getById(patientId);
        if (patient == null) {
            return null;
        }
        LambdaQueryWrapper<DtrdEntQuestionnaireRdReversion> wrapper = Wrappers.lambdaQuery(DtrdEntQuestionnaireRdReversion.class)
                .eq(DtrdEntQuestionnaireRdReversion::getPatientId, patientId)
                .orderByDesc(DtrdEntQuestionnaireRdReversion::getCreateTime)
                .last("limit 1");
        DtrdEntQuestionnaireRdReversion reversion = getOne(wrapper);
        if (reversion == null) {
            return null;
        }
        DtrdEntRdArchiveOverview overview = overviewService.getOne(Wrappers.lambdaQuery(DtrdEntRdArchiveOverview.class)
                .eq(DtrdEntRdArchiveOverview::getPatientId, patientId));
        DtrdEntRdArchivePhysical physical = physicalService.getOne(Wrappers.lambdaQuery(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId));

        QuestionnaireRdVersionDetail dto = new QuestionnaireRdVersionDetail().parseFromPO(patient);
        dto.parseFromPO(reversion);
        if (overview != null) {
            dto.parseFromPO(overview);
        }
        if (physical != null) {
            dto.parseFromPO(physical);
        }
        return dto;
    }

    @Override
    public Integer saveQuestionnaireReversion(QuestionnaireRdVersionDetail dto) {
        Integer patientId = dto.getPatientId();
        DtrdEntQuestionnaireRdReversion reversion = new DtrdEntQuestionnaireRdReversion();
        if (dto.getDataId() == null) {
            reversion = reversion.init();
        }
        reversion.parseFromDTO(dto);
        // 更新 patient 表
        DtrdEntRdPatient patient = new DtrdEntRdPatient();
        patient = patient.parseFromDTO(dto);
        patientService.saveOrUpdate(patient);
        // 更新 overview 表
        DtrdEntRdArchiveOverview overview = new DtrdEntRdArchiveOverview().parseFromDTO(dto);
        overviewService.saveOrUpdateByPatientId(overview, patientId);
        // 更新 physical 表
        DtrdEntRdArchivePhysical physical = new DtrdEntRdArchivePhysical().parseFromDTO(dto);
        physicalService.saveOrUpdateByPatientId(physical, patientId);
        // 设置调查问卷结果
        float bmi = SchemeUtil.getBmi(dto.getHeight(), dto.getWeight());
        long between = DateUtil.between(dto.getDiabetesDiagnosisDate(), new Date(), DateUnit.DAY);
        int result = Constant.ReversionResult.SATISFY_1.getType();
        if (dto.getDiabetesDiagnosis().equals(NO_DIABETES_DIAGNOSE)  // 未确诊
                || !dto.getDiabetesType().equals(Constant.DiabetesType.DIABETES_TYPE_2.getType()) // 不是2型糖尿病
                || (dto.getSex().equals(Constant.Sex.MAN.getType()) && bmi < 25 && dto.getWaistline() <= 90) // 男性且 bmi < 25 腰围 <= 90
                || (dto.getSex().equals(Constant.Sex.WOMAN.getType()) && bmi < 25 && dto.getWaistline() <= 85) // 女性 bmi < 25 腰围 <=85
                || between > 365 * 5 // 病程 > 5 年
                || dto.getCPeptide() < 1.1 // 空腹 C 肽<1.1 μg/L
                || dto.getCPeptide2h() < 2.5 // 餐后2小时 C 肽<2.5 μg/L
        ) {
            result = Constant.ReversionResult.NOT_SATISFY.getType();
        } else if (dto.getDiabetesComplication().equals(DIABETES_COMPLICATION)) {
            List<Integer> symptoms = Arrays.stream(dto.getDiabetesComplicationSymptom().split(","))
                    .map(Integer::parseInt)
                    .collect(Collectors.toList());
            if (!symptoms.contains(KETONE_LESION)) {
                result = Constant.ReversionResult.SATISFY_2.getType();
            } else if (symptoms.contains(KETONE_LESION) && symptoms.size() > SINGLE_CHOICE) {
                result = Constant.ReversionResult.SATISFY_3.getType();
            } else if (symptoms.contains(KETONE_LESION) && symptoms.size() == SINGLE_CHOICE) {
                result = Constant.ReversionResult.SATISFY_4.getType();
            }
        }
        reversion.setResult(result);
        save(reversion);
        // 0 即不可逆转
        if (Constant.ReversionResult.NOT_SATISFY.getType() == result) {
            patientTagService.savePatientTag(patientId, irreversible);
        } else {
            patientTagService.savePatientTag(patientId, reversible);
        }
        return result;
    }

    @Override
    public boolean removeQuestionnaire(Integer dataId) {
        return removeById(dataId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveQuestionnaireInfo(PatientBasicInfo dto) {
        // 保存基础信息
        DtrdEntRdPatient patient = new DtrdEntRdPatient().parseFromDTO(dto);
        patientService.saveOrUpdate(patient);
        archiveBasicService.saveOrUpdatePatientInfo(dto);
        Integer patientId = patient.getDataId();
        // 保存体格检查信息
        DtrdEntRdArchivePhysical physical = new DtrdEntRdArchivePhysical().parseFromDTO(dto);
        physicalService.saveOrUpdate(physical, Wrappers.lambdaUpdate(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId));
        // 糖尿病概况
        DtrdEntRdArchiveOverview overview = new DtrdEntRdArchiveOverview().parseFromDTO(dto);
        overview.setPatientId(patientId);
        overviewService.saveOrUpdate(overview, Wrappers.lambdaQuery(DtrdEntRdArchiveOverview.class)
                .eq(DtrdEntRdArchiveOverview::getPatientId, patientId));
        // 既往病史-通风
        DtrdEntRdArchiveAnamnesis anamnesis = new DtrdEntRdArchiveAnamnesis().parseFromDTO(dto);
        anamnesis.setPatientId(patientId);
        anamnesisService.saveOrUpdate(anamnesis, Wrappers.lambdaQuery(DtrdEntRdArchiveAnamnesis.class)
                .eq(DtrdEntRdArchiveAnamnesis::getPatientId, patientId));
        // 保存逆转问卷数据
        DtrdEntQuestionnaireRdReversion reversion = new DtrdEntQuestionnaireRdReversion().parseFromDTO(dto);
        reversion.setPatientId(patientId);
        msgEventPusher.sendPatientBasicInfoEvent(patientId, patient.getWxOaOpenid(), patient.getDoctorId());
        return saveOrUpdate(reversion, Wrappers.lambdaUpdate(DtrdEntQuestionnaireRdReversion.class)
                .eq(DtrdEntQuestionnaireRdReversion::getPatientId, patientId));
    }

    @Override
    public PatientBasicInfo getPatientBasicInfo(Integer patientId) {
        PatientBasicInfo basicInfo = new PatientBasicInfo();
        DtrdEntRdPatient patient = patientService.getById(patientId);
        if (patient != null) {
            basicInfo = basicInfo.parseFromPO(patient);
        }
        DtrdEntRdArchiveBasic archiveBasic = archiveBasicService.getPatientBasicInfoByPatientId(patientId);
        if (archiveBasic != null) {
            basicInfo.setPatientBodyImage(archiveBasic.getPatientBodyImage());
            basicInfo.setDiseaseProfile(archiveBasic.getDiseaseProfile());
        }
        DtrdEntRdArchiveOverview overview = overviewService.getOne(Wrappers.lambdaQuery(DtrdEntRdArchiveOverview.class)
                .eq(DtrdEntRdArchiveOverview::getPatientId, patientId));
        if (overview != null) {
            basicInfo = basicInfo.parseFromPO(overview);
        }
        DtrdEntRdArchivePhysical physical = physicalService.getOne(Wrappers.lambdaQuery(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getIsDel,0)
                .eq(DtrdEntRdArchivePhysical::getPatientId,patientId));
        if (physical != null){
            basicInfo = basicInfo.parseFromPO(physical);
        }
        DtrdEntRdArchiveAnamnesis anamnesis = anamnesisService.getOne(Wrappers.lambdaQuery(DtrdEntRdArchiveAnamnesis.class)
                .eq(DtrdEntRdArchiveAnamnesis::getIsDel,0)
                .eq(DtrdEntRdArchiveAnamnesis::getPatientId,patientId));
        if (anamnesis != null){
            basicInfo = basicInfo.parseFromPO(anamnesis);
        }
        return basicInfo;
    }

    @Override
    public PatientDetailInfo getPatientDetailInfo(Integer patientId) {
        PatientDetailInfo detailInfo = new PatientDetailInfo(patientId);
        DtrdEntRdArchiveOverview overview = overviewService.getOne(Wrappers.lambdaQuery(DtrdEntRdArchiveOverview.class)
                .eq(DtrdEntRdArchiveOverview::getPatientId, patientId));
        DtrdEntRdArchivePhysical physical = physicalService.getOne(Wrappers.lambdaQuery(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId));
        // overview 在save的basic已经创建，physical为医生端创建, 如果医生创建过
        // 则未填写也都会变成true
//        if (overview != null || physical != null) {
//            detailInfo.setIsFinished(1);
//        }
        if (overview != null) {
            detailInfo.parseFromPO(overview);
//            判断其中一项是否填写，如果该项未填写则判断其未完成，在此判断空腹C肽是否填写
            detailInfo.setIsFinished(null ==overview.getCPeptide()? Constant.UN_FINISHED:Constant.FINISHED);
        }
        if (physical != null) {
            detailInfo.parseFromPO(physical);
        }
        return detailInfo;
    }

    @Override
    public boolean saveOrUpdatePatientDetail(PatientDetailInfo info) {
        Integer patientId = info.getPatientId();
        DtrdEntRdArchivePhysical physical = new DtrdEntRdArchivePhysical().parseFromDTO(info);
        boolean result1 = physicalService.saveOrUpdate(physical, Wrappers.lambdaQuery(DtrdEntRdArchivePhysical.class)
                .eq(DtrdEntRdArchivePhysical::getPatientId, patientId));
        DtrdEntRdArchiveOverview overview = new DtrdEntRdArchiveOverview().parseFromDTO(info);
        boolean result2 = overviewService.saveOrUpdate(overview, Wrappers.lambdaQuery(DtrdEntRdArchiveOverview.class)
                .eq(DtrdEntRdArchiveOverview::getPatientId, patientId));
        return result1 && result2;
    }

    private LambdaQueryWrapper<DtrdEntQuestionnaireRdReversion> baseQueryWrapper() {
        return Wrappers.lambdaQuery(DtrdEntQuestionnaireRdReversion.class)
                .eq(DtrdEntQuestionnaireRdReversion::getIsDel, 0);
    }

    private LambdaUpdateWrapper<DtrdEntQuestionnaireRdReversion> baseUpdateWrapper() {
        return Wrappers.lambdaUpdate(DtrdEntQuestionnaireRdReversion.class)
                .eq(DtrdEntQuestionnaireRdReversion::getIsDel, 0);
    }
}
